package com.example.gfile.util;


import com.example.gfile.entity.Sftp;
import com.example.gfile.exception.GFileException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.function.Consumer;

public class JSchUtil {

    private final Logger LOG = LoggerFactory.getLogger(getClass());

    /**
     * 上传来之html页面的文件到远程服务器(此方法上传文件后,文件名不变)
     */
    public Consumer<SftpDto> uploadFile() {
        return sftpDto -> {
            ChannelSftp channel = sftpDto.getChannel();
            try {
                channel.cd(sftpDto.getSftp().getUploadPath());
                // 使用put方法,两个参数路径都是绝对的
                channel.put(sftpDto.getFile().getAbsolutePath(), sftpDto.getFile().getName());
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                throw new GFileException("文件上传失败", e);
            }
        };
    }

    /**
     * 上传文件到远程服务器(此方法上传文件后,文件名不变)
     */
    public Consumer<SftpDto> uploadFromHtmlFile() {
        return sftpDto -> {
            ChannelSftp channel = sftpDto.getChannel();
            try {
                channel.cd(sftpDto.getSftp().getUploadPath());
                // 使用put方法,两个参数路径都是绝对的
                channel.put(sftpDto.getMultipartFile().getInputStream(), sftpDto.getMultipartFile().getOriginalFilename());
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                throw new GFileException("文件上传失败", e);
            }
        };
    }

    /**
     * 关闭连接
     */
    public Consumer<SftpDto> close() {
        return sftpDto -> {
            ChannelSftp channel = sftpDto.getChannel();
            Session session = sftpDto.getSession();
            if (channel != null) {
                channel.disconnect();
                channel.exit();
            }
            if (session != null) {
                session.disconnect();
            }
        };
    }

    /**
     * 初始化连接
     */
    public Consumer<SftpDto> initialize() {
        return sftpDto -> {
            try {
                Sftp sftp = sftpDto.getSftp();
                JSch jsch = new JSch();
                Session session = jsch.getSession(sftp.getUserName(), sftp.getHost(), sftp.getPort());
                session.setPassword(sftp.getPassword());
                session.setConfig("StrictHostKeyChecking", "no");
                session.connect();
                ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
                sftpDto.setSession(session);
                sftpDto.setChannel(channel);
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                throw new GFileException("初始化sftp连接失败", e);
            }
        };
    }

    /**
     * 创建多级目录并cd到该目录下
     */
    public Consumer<SftpDto> mkdir() {
        return sftpDto -> {
            ChannelSftp channel = sftpDto.getChannel();
            String remotePath = sftpDto.getSftp().getUploadPath();
            try {
                channel.connect();
                String[] folders = remotePath.split("/");
                if (remotePath.startsWith("/")) {
                    channel.cd("/");
                }
                for (String folder : folders) {
                    if (folder.length() > 0) {
                        try {
                            channel.cd(folder);
                        } catch (SftpException e) {
                            channel.mkdir(folder);
                            channel.cd(folder);
                        }
                    }
                }
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                throw new GFileException("创建文件夹异常", e);
            }
        };
    }

    @Data
    public static class SftpDto {

        private Sftp sftp;
        private MultipartFile multipartFile;
        private File file;
        private String fileName;
        private Session session;
        private ChannelSftp channel;
    }

}
